#pragma once

#include <MCF/Code/StdMCF.hpp>
#include <MCF/Code/ModelessDialogClass.hpp>
#include <MCF/Code/EventHandlerClass.hpp>
#include <vector>
#include <forward_list>
#include "GeneralDefinitions.hpp"

class KeyboardClass sealed : public MCF::ModelessDialogClass {
private:
	enum : UINT {
		_MSG_UPDATE = WM_USER + 0x1000
	};
private:
	static HHOOK _s_hLowLevelKeyboardHook;
	static std::forward_list<KeyboardClass *> _s_lstInstances;
	static MCF::CriticalSection _s_csHookLock;
private:
	static bool _EventPopProc(std::intptr_t nContext, std::intptr_t nArg1, std::intptr_t nArg2, std::intptr_t nArg3);
	static bool _EventClearProc(std::intptr_t nContext, std::intptr_t nArg1, std::intptr_t nArg2, std::intptr_t nArg3);

	static std::vector<WORD> _MapScanCodes(BYTE byScanCode, bool bIsExtended, bool bIsMakeCode);
	static LRESULT CALLBACK _LowLevelKeyboardProc(int nCode, WPARAM wParam, LPARAM lParam);
private:
	MCF::CriticalSection _m_csLock;
	WORD _m_arwBuffer[0x10];
	std::size_t _m_uBeforeFront;
	std::size_t _m_uBack;

	volatile long _m_lInvalidated;
public:
	KeyboardClass();
	~KeyboardClass();
protected:
	virtual void _PostSubclass() override;
	virtual void _PreUnsubclass() override;

	virtual LRESULT _OnMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) override;

	virtual bool _OnInitDialog(HWND hDefControl, LPARAM lInitParam) override;
	virtual bool _OnCommand(WORD wNotifyCode, int nControlID, HWND hSender) override;
private:
	// NTS = Non Thread Safe
	bool _IsFullNTS() const;
	bool _IsEmptyNTS() const;
	DWORD _PeekFrontNTS() const;

	bool _Push(WORD wCode);
	DWORD _Pop();
	void _Clear();
};
